﻿using DevExpress.Data.Filtering;
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.DC;
using DevExpress.Persistent.Base;
using DevExpress.Persistent.Validation;

namespace EasyXaf.ExcelImporters;

public static class ModelImportingMemberExtensions
{
    public static string GetCaption(this IModelImportingMember importingMemberModel)
    {
        var caption = importingMemberModel.Caption;
        if (string.IsNullOrWhiteSpace(caption))
        {
            caption = importingMemberModel.Property.Caption;
        }
        if (string.IsNullOrWhiteSpace(caption))
        {
            caption = importingMemberModel.Property.Name;
        }
        return caption;
    }

    public static bool IsRequired(this IModelImportingMember importingMemberModel)
    {
        var memberType = importingMemberModel.Property.Type;
        if (memberType.IsValueType && !memberType.IsGenericType)
        {
            return true;
        }
        var memberInfo = importingMemberModel.Property.MemberInfo;
        return memberInfo.FindAttribute<RuleRequiredFieldAttribute>() != null;
    }

    public static bool IsNullableType(this IModelImportingMember importingMemberModel)
    {
        var memberType = importingMemberModel.Property.Type;
        if (memberType.IsGenericType && memberType.GetGenericTypeDefinition() == typeof(Nullable<>))
        {
            return true;
        }
        return false;
    }

    public static bool IsImageType(this IModelImportingMember importingMemberModel)
    {
        if (importingMemberModel.Property.Type == typeof(byte[]))
        {
            if (importingMemberModel.Property.MemberInfo.FindAttribute<ImageEditorAttribute>() != null)
            {
                return true;
            }
        }
        return false;
    }

    private static bool IsAssociation(this IMemberInfo memberInfo)
    {
        // 在EFCore中，导航属性与反向导航属性都存在的情况下IsAssociation为Ture，否则为False，所以这里不能使用IsAssociation
        // return memberInfo.IsAssociation;

        // 如果包含在TypesInfo的PersistentTypes（包含了持久化与非持久化实体，这里不去区分）中，就表示是关系实体
        var memberTypeInfo = memberInfo.IsList ? memberInfo.ListElementTypeInfo : memberInfo.MemberTypeInfo;
        return XafTypesInfo.Instance.PersistentTypes.Any(t => memberTypeInfo == t);
    }

    public static bool IsReferenceType(this IModelImportingMember importingMemberModel)
    {
        var memberInfo = importingMemberModel.Property.MemberInfo;
        return memberInfo.IsAssociation() && !memberInfo.IsList;
    }

    public static bool IsCollectionType(this IModelImportingMember importingMemberModel)
    {
        var memberInfo = importingMemberModel.Property.MemberInfo;
        return memberInfo.IsAssociation() && memberInfo.IsList;
    }

    public static Type GetMemberRealType(this IModelImportingMember importingMemberModel)
    {
        var memberType = importingMemberModel.Property.Type;
        if (memberType.IsGenericType && memberType.GetGenericTypeDefinition() == typeof(Nullable<>))
        {
            memberType = memberType.GenericTypeArguments[0];
        }
        return memberType;
    }

    public static IEnumerable<string> GetBooleanValueTexts(this IModelImportingMember importingMemberModel)
    {
        var property = importingMemberModel.Property;
        var values = new List<string>
        {
            string.IsNullOrWhiteSpace(property.CaptionForFalse) ? "否" : property.CaptionForFalse,
            string.IsNullOrWhiteSpace(property.CaptionForTrue) ? "是" : property.CaptionForTrue,
        };
        return values;
    }

    public static IEnumerable<string> GetDataSourceTexts(this IModelImportingMember importingMemberModel, IObjectSpace objectSpace)
    {
        if (importingMemberModel.IsReferenceType())
        {
            var dataSourceCriteria = importingMemberModel.DataSourceCriteria;
            if (!string.IsNullOrWhiteSpace(dataSourceCriteria))
            {
                var memberInfo = importingMemberModel.Property.MemberInfo;
                var memberType = importingMemberModel.Property.Type;
                var defaultMember = memberInfo.MemberTypeInfo.DefaultMember;
                var objects = objectSpace.GetObjects(memberType, CriteriaOperator.Parse(dataSourceCriteria));
                return objects.Cast<object>().Select(obj => defaultMember.GetValue(obj) + string.Empty).ToList();
            }
        }
        return Array.Empty<string>();
    }

    public static string GetDataSourceSheetName(this IModelImportingMember importingMemberModel)
    {
        if (importingMemberModel.IsReferenceType())
        {
            return $"R-{importingMemberModel.Property.Name}";
        }
        return string.Empty;
    }
}
